﻿/*
 * @author: wizardc
 */

using System;
using Cysharp.Threading.Tasks;
using Dou.Utils;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Dou.Resource
{
    /// <summary>
    /// 资源管理器
    /// </summary>
    public sealed class AssetManager
    {
        private static AssetManager _instance;
        public static AssetManager instance => _instance ??= new AssetManager();
        
        private bool _initialized = false;
        private AssetLoadType _loadType;
        private IAssetLoader _assetLoader;

        private AssetManager()
        {
        }

        /// <summary>
        /// AB 包加载最大线程数量
        /// </summary>
        public int maxLoadABThread
        {
            set => _assetLoader.maxLoadABThread = value;
            get => _assetLoader.maxLoadABThread;
        }

        /// <summary>
        /// 资源加载最大线程数量
        /// </summary>
        public int maxLoadAssetThread
        {
            set => _assetLoader.maxLoadABThread = value;
            get => _assetLoader.maxLoadABThread;
        }
        
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="isEncrypt">AB 包是否开启加密</param>
        public void Init(AssetLoadType loadType, bool isEncrypt, Action onComplete, AssetUnloadSetting[] unloadSettings = null)
        {
            if (_initialized)
            {
                Log.Error("AssetManager 重复初始化！");
                return;
            }
            _initialized = true;
            _loadType = loadType;
            switch (_loadType)
            {
                case AssetLoadType.AssetDatabase:
#if UNITY_EDITOR
                    _assetLoader = new AssetDatabaseLoader();
#endif
                    break;
                case AssetLoadType.AssetBundle:
                    _assetLoader = new AssetBundleLoader();
                    break;
            }
            _assetLoader.Init(isEncrypt, onComplete, unloadSettings);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public async UniTask InitAsync(AssetLoadType loadType, bool isEncrypt, AssetUnloadSetting[] unloadSettings = null)
        {
            var isComplete = false;
            Init(loadType, isEncrypt, () =>
            {
                isComplete = true;
            }, unloadSettings);
            await UniTask.WaitUntil(() => isComplete);
        }

        /// <summary>
        /// 异步加载 AB 包
        /// </summary>
        public void LoadAssetBundle(string name, Action<AssetBundle> onComplete, int priority = 0)
        {
            _assetLoader.LoadAssetBundle(name, onComplete, priority);
        }

        /// <summary>
        /// 异步加载 AB 包
        /// </summary>
        public async UniTask<AssetBundle> LoadAssetBundleAsync(string name, int priority = 0)
        {
            AssetBundle result = null;
            var isComplete = false;
            LoadAssetBundle(name, (ab) =>
            {
                result = ab;
                isComplete = true;
            }, priority);
            await UniTask.WaitUntil(() => isComplete);
            return result;
        }

        /// <summary>
        /// 同步加载 AB 包
        /// </summary>
        public void LoadAssetBundleSync(string name, Action<AssetBundle> onComplete, int priority = 0)
        {
            _assetLoader.LoadAssetBundleSync(name, onComplete, priority);
        }

        /// <summary>
        /// 获取已经加载完毕的 AB 包对象
        /// </summary>
        public AssetBundle GetAssetBundle(string name)
        {
            return _assetLoader.GetAssetBundle(name);
        }

        /// <summary>
        /// 卸载AB包
        /// </summary>
        /// <param name="force">true：强制卸载，false：必须引用次数为 0 时才能卸载</param>
        public void UnloadAssetBundle(string name, bool force = false)
        {
            _assetLoader.UnloadAssetBundle(name, force);
        }
        
        /// <summary>
        /// 增加引用
        /// </summary>
        public void AddRef(string abName, int count = 1)
        {
            _assetLoader.AddRef(abName, count);
        }

        /// <summary>
        /// 减少引用
        /// </summary>
        public void DecRef(string abName, int count = 1)
        {
            _assetLoader.DecRef(abName, count);
        }

        /// <summary>
        /// 基于资源名增加引用
        /// 注意：最终增加的是 AB 包的引用次数
        /// </summary>
        public void AddAssetRef(string assetName, int count = 1)
        {
            _assetLoader.AddAssetRef(assetName, count);
        }

        /// <summary>
        /// 基于资源名减少引用
        /// 注意：最终减少的是 AB 包的引用次数
        /// </summary>
        public void DecAssetRef(string assetName, int count = 1)
        {
            _assetLoader.DecAssetRef(assetName, count);
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        public void LoadAsset(string name, Action<Object> onComplete, int priority = 0)
        {
            LoadAsset(name, typeof(Object), onComplete, priority);
        }
        
        /// <summary>
        /// 异步加载资源
        /// </summary>
        public void LoadAsset(string name, Type type, Action<Object> onComplete, int priority = 0)
        {
            _assetLoader.LoadAsset(name, type, onComplete, priority);
        }
        
        /// <summary>
        /// 异步加载资源
        /// </summary>
        public void LoadAsset<T>(string name, Action<T> onComplete, int priority = 0) where T : Object
        {
            LoadAsset(name, typeof(T), obj => { onComplete((T) obj); }, priority);
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        public async UniTask<Object> LoadAssetAsync(string name, int priority = 0)
        {
            return await LoadAssetAsync<Object>(name, priority);
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        public async UniTask<T> LoadAssetAsync<T>(string name, int priority = 0) where T : Object
        {
            T result = null;
            var isComplete = false;
            LoadAsset<T>(name, asset =>
            {
                result = asset;
                isComplete = true;
            }, priority);
            await UniTask.WaitUntil(() => isComplete);
            return result;
        }

        /// <summary>
        /// 同步加载资源
        /// </summary>
        public void LoadAssetSync(string name, Action<Object> onComplete, int priority = 0)
        {
            LoadAssetSync(name, typeof(Object), onComplete, priority);
        }

        /// <summary>
        /// 同步加载资源
        /// </summary>
        public void LoadAssetSync(string name, Type type, Action<Object> onComplete, int priority = 0)
        {
            _assetLoader.LoadAssetSync(name, type, onComplete, priority);
        }
        
        /// <summary>
        /// 同步加载资源
        /// </summary>
        public void LoadAssetSync<T>(string name, Action<T> onComplete, int priority = 0) where T : Object
        {
            LoadAssetSync(name, typeof(T), obj => { onComplete((T) obj); }, priority);
        }

        /// <summary>
        /// 卸载资源
        /// 注意：该方法只会将 AB 包的引用次数减 1，并不会真正的销毁加载的资源，加载的资源销毁清自行控制
        /// </summary>
        public void UnloadAsset(string name)
        {
            _assetLoader.UnloadAsset(name);
        }

        /// <summary>
        /// 异步加载预制
        /// </summary>
        public void LoadPrefab(string name, Action<GameObject> onComplete, int priority = 0)
        {
            _assetLoader.LoadPrefab(name, onComplete, priority);
        }

        /// <summary>
        /// 异步加载预制
        /// </summary>
        public async UniTask<GameObject> LoadPrefabAsync(string name, int priority = 0)
        {
            GameObject result = null;
            var isComplete = false;
            LoadPrefab(name, gameObject =>
            {
                result = gameObject;
                isComplete = true;
            }, priority);
            await UniTask.WaitUntil(() => isComplete);
            return result;
        }
        
        /// <summary>
        /// 同步加载预制
        /// </summary>
        public void LoadPrefabSync(string name, Action<GameObject> onComplete, int priority = 0)
        {
            _assetLoader.LoadPrefabSync(name, onComplete, priority);
        }

        /// <summary>
        /// 卸载掉不使用的AB包
        /// </summary>
        public void UnloadUnusedAB()
        {
            _assetLoader.UnloadUnusedAB();
        }

        /// <summary>
        /// 根据 AB 包名获取混淆后的 AB 包名
        /// </summary>
        public string GetAssetBundleName(string name)
        {
            return _assetLoader.GetAssetBundleName(name);
        }

        /// <summary>
        /// 根据文件名获取该文件在 AB 包中的完整文件路径名
        /// </summary>
        public string GetAssetFullPath(string name)
        {
            return _assetLoader.GetAssetFullPath(name);
        }

        /// <summary>
        /// 根据文件名获取原始拷贝文件路径（用于流式加载的文件，如 MP4 或者需要流式加载的自定义数据文件等）
        /// </summary>
        public string GetRawAssetPath(string name)
        {
            return _assetLoader.GetRawAssetPath(name);
        }
    }
}
